/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://git.oschina.net/cblock/embedme
 * Copyright 2014~2020 @ ShenZhen ,China
*******************************************************************************/
#include "Tracer.h"
#include "StrUtil.h"
#include "FileUtil.h"

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <ctype.h>
#include <libgen.h>

namespace libemb{
using namespace std;/**
 *  \brief  将字符串转换为小写
 *  \param  str 源字符串
 *  \return 返回转换好的字符串
 *  \note   none
 */
std::string StrUtil::toLower(const char* str)
{
    std::string rc="";
    int i=0;
    char ch = *(str+i);
    while(ch!=0)
    {
        rc.append(1,(char)tolower(ch));
        ch = *(str+(++i));
    }
    return rc;
}
/**
 *  \brief  将字符串转换为大写
 *  \param  str 源字符串
 *  \return 返回转换好的字符串
 *  \note   none
 */
std::string StrUtil::toUpper(const char* str)
{
    std::string rc="";
    int i=0;
    char ch = *(str+i);
    while(ch!=0)
    {
        rc.append(1,(char)toupper(ch));
        ch = *(str+(++i));
    }
    return rc;
}
/**
 *  \brief  字符串格式化
 *  \param  fmt 格式化字符串
 *  \return 返回转换好的字符串
 *  \note   将C风格字符串格式化为string,最长1024字节
 */
string StrUtil::stringFormat(const char * fmt, ...)
{
    va_list argp;
    va_start(argp, fmt);
    char buf[1024]={0};
    vsnprintf(buf,1023, fmt, argp);
    va_end(argp);
    return std::string(buf);
}

/**
 *  \brief  用rep替换source中的str
 *  \param  source 源字串
 *  \param  str 被替换字符串
 *  \param  rep 替换字符串
 *  \return 返回新字符串
 *  \note   none
 */
std::string StrUtil::replaceString(const string& source,const string str,const string rep)
{
    std::string result="";
    uint32 pos=0;
    while (1) 
    {
        int findPos = source.find(str,pos);
        if (findPos!=std::string::npos) 
        {
            result.append(source,pos,findPos-pos);
            result.append(rep);
            pos = findPos + str.size();
        }
        else
        {
            result.append(source,pos,source.size()-pos);
            break;
        }
    }
    return result;
}
/**
 *  \brief  查找start开始与end结束的字符串
 *  \param  source 源字串
 *  \param  start 开始字串
 *  \param  end 结束字串
 *  \return 返回找到的字符串
 *  \note   none
 */
std::string StrUtil::findString(const string& source, const string& start, const string& end)
{
	std::string restStr;
	uint32 startPos,endPos;
	/* 找出匹配关键字 */
	startPos = source.find(start,0);
	if (startPos==string::npos)
	{
		TRACE_DBG("StrUtil::findString,no start[%s]...\n",CSTR(start));
		return "";
	}

	endPos = source.find(end,1);
	if (endPos==string::npos)
	{
		TRACE_DBG("StrUtil::findString,no end[%s]...\n",CSTR(end));
		return "";
	}

	return source.substr(startPos,endPos-startPos+end.size());
}

/**
 *  \brief  查找匹配字段
 *  \param  source 源字串
 *  \param  pattern 匹配字串
 *  \param  before 匹配字串之前的字串
 *  \param  after 匹配字串之后的字串
 *  \return 返回找到的字符串
 *  \note   none
 */
string StrUtil::findString(const string& source, const string& pattern, const string& before, const string& after)
{
	std::string restStr;
	uint32 startPos,endPos;
	/* 找出匹配关键字 */
	startPos = source.find(pattern,0);
	if (startPos==string::npos)
	{
		TRACE_DBG("StrUtil::findString,no pattern[%s]...\n",CSTR(pattern));
		return "";
	}

	/* 从匹配关键字开始查找字符串 */
	restStr = source.substr(startPos);
	startPos = restStr.find(before,0);
	if (startPos==string::npos)
	{
		TRACE_DBG("StrUtil::findString,no before[%s]...\n",CSTR(before));
		return "";
	}
	/* 跳过before字串 */
	startPos += before.size();
	endPos = restStr.find(after,startPos);
	if (endPos==string::npos)
	{
		TRACE_DBG("StrUtil::findString,no after[%s]...\n",CSTR(after));
		return "";
	}
	/* 截取before与after之间的字串 */
	return restStr.substr(startPos,endPos-startPos);
}

/**
 *  \brief  从字符串头部去除trimch包含的字符,直至遇到非trimch字符为止
 *  \param  source 源字串
 *  \return 返回trim后得到的字符串
 *  \note   例:result = trimHeadWith(" 0001234","0 ");//result="1234"
 */
string StrUtil::trimHeadWith(const string& source,const string& trimch)
{
    std::string result;
    int len=source.size();
    int trimLen = trimch.size();
    int i=0;
    while(i<len)
    {
        int j;
        for(j=0;j<trimLen;j++)
        {
            if (source[i]==trimch[j])
            {
                break;
            }
        }
        if (j==trimLen)
        {
            result=source.substr(i);
            break;
        }
        i++;
    }
    return result;
}
/**
 *  \brief  去除字符串首尾两端的不可见字符
 *  \param  source 源字串
 *  \param  trimHead 是否去除头部,默认为true
 *  \param  trimTail 是否去除尾部,默认为true
 *  \return 返回trim后得到的字符串
 *  \note   none
 */
std::string StrUtil::trimTailBlank(const string& source,bool trimHead, bool trimTail)
{
	std::string result;
    if (trimHead) 
    {
        int len = source.size();
        for(auto i =0;i<len; i++)
        {
            if (source[i]>32)
            {
                result=source.substr(i);
                break;
            }
        }
    }
    if (trimTail) 
    {
        int len = result.size();
        for(auto i=0; i<len; i++)
        {
            if (result[len-1-i]>32)
            {
                result=result.substr(0,len-i);
                break;
            }
        }
    }
	return result;
}

/**
 *  \brief  去除字符串中所有不可见字符
 *  \param  source 源字串
 *  \return 返回trim后得到的字符串
 *  \note   none
 */
std::string StrUtil::trimAllBlank(const string& source)
{
    int i=0;
    int len=source.size();
    std::string result="";
    while(i<len)
    {
        if (source[i]>32)
        {
            result.append(1,source[i]);
        }
        i++;
    }
    return result;
}

/**
 *  \brief  从头开始获取可见字符，到第一个不可见字符结束；
 *  \param  source 源字串
 *  \return 返回截取的字符串
 *  \note   例:result = trimHeadUnvisible("000123 4");//result="000123"
 */
string StrUtil::trimHeadUnvisible(const string& source)
{
    int i=0;
    int len=source.size();
    std::string result="";
    while(i<len)
    {
        if (source[i]>32)
        {
            result.append(1,source[i]);
        }
        else
        {
        	break;
        }
        i++;
    }
    return result;
}

/**
 *  \brief  拆分字符串
 *  \param  source 源字串
 *  \param  splitFlag 拆分符
 *  \param  withFlag 是否包含拆分符
 *  \return 返回拆分后的字串数组
 *  \note   以splitFlag为标识拆分整个字串
 */
vector<string> StrUtil::splitString(const string& source,const string& splitFlag,bool withFlag)
{
    vector<string> vecResult;
    if (source.empty())
    {
        return vecResult;
    }
    if (splitFlag.empty())
    {
        vecResult.push_back(source);
        return vecResult;
    }
    int startPos = 0;
    int findPos = source.find(splitFlag, 0);
    while (findPos!=string::npos)
    {
        if (findPos!=startPos)
        {
            vecResult.emplace_back(source.substr(startPos,findPos-startPos));
        }
        if (withFlag)
        {
            vecResult.emplace_back(source.substr(findPos, splitFlag.size()));
        }
        startPos = findPos + splitFlag.size();
        findPos = source.find(splitFlag, startPos);
    }
    if (startPos < source.size())
    {
        vecResult.emplace_back(source.substr(startPos,source.size()-startPos));
    }
    return vecResult;
}
/**
 *  \brief  分割字符串
 *  \param  source 源字串
 *  \return 返回分割后的字串数组(不包括分割符)
 *  \note   分割从startFlag后到endFlag之前的字串,分割符为cutFlag,例：
 *          s="+ABC:1,2,3,,,6,7\r"  ==> cutString(s,"+ABC:","\r",",")
 *          返回结果:["1","2","3","","","6","7"]
 */
vector<string> StrUtil::cutString(const string& source,const string& startFlag,const string& endFlag,const string& cutFlag)
{
    vector<string> vecResult;
    int startPos = source.find(startFlag);
	int endPos = source.find(endFlag);
    if (source.empty() || 
        startFlag.empty() || 
        endFlag.empty() || 
        cutFlag.empty() || 
        startPos == string::npos ||
        endPos ==string::npos )
    {
        return vecResult;
    }
    startPos += startFlag.length();
	if (endPos <= startPos)
	{
		return vecResult;
	}

	int searchPos;
	while (endPos != string::npos && endPos > startPos || endPos == string::npos)
	{
		searchPos = source.find(cutFlag, startPos);
		if (searchPos == string::npos)
		{
			if (endPos != string::npos)
				vecResult.emplace_back(source.substr(startPos, endPos-startPos));
			else
				vecResult.emplace_back(source.substr(startPos));
			break;
		}
		vecResult.emplace_back(source.substr(startPos, searchPos-startPos));
		startPos = searchPos + cutFlag.length();
	}
	return vecResult;
}
/**
 *  \brief  获取匹配次数
 *  \param  source 源字串
 *  \param  pattern 匹配字串
 *  \return 返回匹配次数
 *  \note   none
 */
int StrUtil::patternCount(const string& source, const string& pattern)
{
	int atFind=0;
	int i =0;
	if(source.empty() || pattern.empty())
	{
		return 0;
	}
	while(1)
	{
		atFind = source.find(pattern,atFind);
		if(atFind!=string::npos)
		{
			atFind += pattern.size();
			i++;
		}
		else
		{
			break;
		}
	}
	return i;
}

/**
 *  \brief  ASCII码转换为数字
 *  \param  ch ASCII码字符
 *  \return ch对应的数字
 *  \note   字符'0'~'9'转换后为数字0~9,'a'~'f'或'A'~'F'转换后为10~16,其余返回值为-1
 */
int StrUtil::charToInt(char ch)
{
	if(ch>='a' && ch <='f')
	{
		return (ch-'a'+0x0A);
	}
	else if(ch>='A' && ch <='F')
	{
		return (ch-'A'+0x0A);
	}
	else if(ch>='0' && ch<='9')
	{
		return (ch-'0');
	}
	else
	{
		return -1;
	}
}

/**
 *  \brief  数字转换为ASCII码
 *  \param  val 数字
 *  \return 数字对应的ASCII码字符
 *  \note   数字0~9转成字符'0'~'9',数字10~16转成'A'~'F',其余返回值为0,为字符串结束符
 */
char StrUtil::intToChar(int val)
{
	if(val>=0 && val<=9)
	{
		return (val+'0');
	}
	else if(val>=0x0A && val<=0x0F)
	{
		return (val-0x0A+'A');
	}
	else
	{
		return 0;
	}
}

/**
 *  \brief  16进制字符串转为二进制字节
 *  \param  hexStr 待转换16进制字符串
 *  \param  bytesBuf 转换好的编码缓存
 *  \param  len 缓存大小
 *  \return 成功返回转换结果的长度,失败返回STATUS_ERROR
 *  \note   "0041001F"  ==>[0x00][0x41][0x00][0x1F]
 */
int StrUtil::hexBinarize(const std::string hexStr,char* buffer,int len)
{
	int i;
	if (hexStr.empty() ||
		NULL==buffer)
	{
		TRACE_ERR("StrUtil::hexBinarize parameter error.\n");
		return RC_ERROR;
	}
	if (len < hexStr.size()/2)
	{
		TRACE_ERR("StrUtil::hexBinarize buf len(%d) error.\n",len);
		return RC_ERROR;
	}

	for(i=0; i<hexStr.size()/2; i++)
	{
		sint8 a,b;
		a=StrUtil::charToInt(hexStr[2*i]);
		b=StrUtil::charToInt(hexStr[2*i+1]);
		if(-1==a || -1==b)
		{
			TRACE_ERR("StrUtil::hexBinarize invalid string.\n");
			return RC_ERROR;
		}
		buffer[i]=(a<<4)+b;
	}
	return i;
}

/**
 *  \brief  编码转为可视字符串
 *  \param  codebuf 待转换的编码缓存
 *  \param  len 缓存大小
 *  \return 成功返回转换后的字符串,失败返回空字符串
 *  \note   [0x00][0x41][0x00][0x1F]==>"0041001F"
 */
std::string StrUtil::hexVisualize(const char* buffer,int len)
{
	if (buffer==NULL || len<=0)
	{
		TRACE_ERR("StrUtil::hexVisualize parameter error.\n");
		return "";
	}

	std::string hexStr="";
	for(auto i=0; i<len; i++)
	{
		char hex[3]={0};
		hex[0] = StrUtil::intToChar((buffer[i]>>4)&0x0F);
		hex[1] = StrUtil::intToChar(buffer[i]&0x0F);
		if (0==hex[0] || 0==hex[1])
		{
			TRACE_ERR("StrUtil::hexVisualize unicode error.\n");
			return "";
		}
		hexStr += hex;
	}
	return hexStr;
}
/**
 *  \brief  16进制字符串转换为数字
 *  \param  16进制字符串
 *  \return 返回计算结果
 *  \note
 */
int StrUtil::hexStrToInt(const char* hexStr)
{
    int result=0;
    char* pHex =  (char*)hexStr;
    while((*pHex)!='\0')
    {
        result = (result<<4)+StrUtil::charToInt(*pHex);
        pHex++;
    }
    return result;
}

int StrUtil::stringToInt(std::string intStr)
{
    return atoi(CSTR(intStr));
}

string StrUtil::intToString(int num)
{
	char buf[32]={0};
	sprintf(buf,"%d",num);
	string numStr(buf);
	return numStr;
}

bool StrUtil::isHexString(const char* hexStr)
{
    int len = strlen(hexStr);
    int i=0;
    while (i<len) 
    {
        if ((*(hexStr+i)>='0' && *(hexStr+i)<='9') ||
            (*(hexStr+i)>='A' && *(hexStr+i)<='F') ||
            (*(hexStr+i)>='a' && *(hexStr+i)<='f'))
        {
            i++;
            continue;
        }
        else
        {
            return false;
        }
    }
    return true;
}
bool StrUtil::isIntString(const char* intStr)
{
    int len = strlen(intStr);
    int i=0;
    while (i<len) 
    {
        if (*(intStr+i)>='0' && *(intStr+i)<='9')
        {
            i++;
            continue;
        }
        else
        {
            return false;
        }
    }
    return true;
}

/******************************************************************************
 * parseNextSection  解析下一个字段
 * source    : 要解析的字符串
 * startPos  : 开始解析的位置
 * endflag   : 下一个结束标识
 * sectionLen: 解析出来的字段长度(只有在返回值非NULL的情况下才有效) 
 * return    : 返回查找字段的首地址,如果没有查找到字段,则返回NULL
 *****************************************************************************/
char* StrUtil::parseNextSection(const char* source,uint32* startPos,const char* endflag,uint32* sectionLen)
{
    unsigned int len = 0;
    char* pstart = (char*)(source + *startPos);
    char* ptr = pstart;
    while((*ptr != *endflag) && (*ptr != 0))
    {
        ptr++;
    }
    len = ptr-pstart;
    if(len==0)
    {
        return NULL;
    }
    *sectionLen = len;
    if(*ptr == 0)
    {
        *startPos += len;      
    }
    else if(*ptr == *endflag)
    {
        *startPos = *startPos+len+1;
    }
    return pstart;
}
/******************************************************************************
 * parseNextString  解析下一个字符串
 * source   : 要解析的字符串
 * startPos : 开始解析的位置
 * endflag  : 下一个结束标识
 * strbuf   : 解析出来的字符串缓存
 * buflen   : 字符串缓存长度
 * return   : 成功返回true,失败返回false
 *****************************************************************************/
bool StrUtil::parseNextString(const char* source,uint32* startPos, const char* endflag, char* strbuf,uint32 buflen)
{
    unsigned int sectionLen=0;
    char* sectionStart=NULL;
    sectionStart = parseNextSection(source, startPos, endflag, &sectionLen);
    if (sectionStart==NULL)
    {
        return false;
    }
    if(sectionLen>0 && sectionLen<buflen)
    {
        memset(strbuf,0,buflen);
        strncpy(strbuf,sectionStart,sectionLen);
        return true;
    }
    return false;   
}
/******************************************************************************
 * parseNextInt  解析下一个整数
 * source   : 要解析的字符串
 * startPos : 开始解析的位置
 * endflag  : 下一个结束标识
 * result   : 解析出来的整数
 * return   : 成功返回true,失败返回false
 *****************************************************************************/
bool StrUtil::parseNextInt(const char* source,uint32* startPos,const char* endflag,sint32* result)
{
    char section[32]={0};
    if (!parseNextString(source, startPos, endflag, section, sizeof(section)))
    {
        return false;
    }
    *result = atoi(section);
    return true;
}


}
